/**
 * All rights Reserved, Designed By OprCalf
 * Copyright:    Copyright(C) 2016-2020
 * Company       BSL Ltd.
 */

package com.platform.gateway.common.filter;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.platform.gateway.common.utils.MsgUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * @projectName:  platform-gateway-demo
 * @package:      com.platform.gateway.common.filters
 * @className:    LimitFilter.java
 * @description:  限流过滤
 * @author:       OprCalf
 * @date:         2020年3月4日
 */
@Component
@Slf4j
public class LimitFilter extends ZuulFilter {

    // 每秒产生100个令牌
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(100);

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return Integer.MIN_VALUE + 2;
    }

    @Override
    public boolean shouldFilter() {
        final RequestContext ctx = RequestContext.getCurrentContext();
        // 当发生异常的时候,不是进行取值
        if (ctx.getThrowable() != null) {
            log.error("{}", ctx.getThrowable().fillInStackTrace());
            if (ctx.sendZuulResponse()) {
                return true;
            } else {
                return false;
            }
        } else {
            return true;
        }
    }

    @Override
    public Object run() throws ZuulException {
        final RequestContext requestContext = RequestContext.getCurrentContext();
        // 就相当于每调用一次tryAcquire()方法，令牌数量减1，当1000个用完后，那么后面进来的用户无法访问上面接口
        // 当然这里只写类上面一个接口，可以这么写，实际可以在这里要加一层接口判断。
        if (!RATE_LIMITER.tryAcquire()) {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
            final HttpServletResponse response = requestContext.getResponse();
            response.setContentType("application/json;charset=UTF-8");
            try {
                response.getOutputStream()
                        .write(MsgUtils.buildFailureMsg("访问量巨大,稍后再试").toString().getBytes("utf-8"));
            }
            catch (final IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
